package ai.people.core.pool.config;

import ai.people.core.pool.properties.ThreadPoolProperties;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.*;

/**
 * 池自动配置
 *
 * @author yuanqinglong
 * @date 2022/3/1 13:48
 */
@Configuration
@EnableConfigurationProperties(value = ThreadPoolProperties.class)
public class PoolAutoConfiguration {


    Logger logger = LoggerFactory.getLogger(PoolAutoConfiguration.class);

    /**
     * 线程池
     *
     * @param properties 属性
     * @return {@link ExecutorService}
     */
    @Bean
    public ExecutorService defaultThreadPoolExecutor(ThreadPoolProperties properties, RejectedExecutionHandler rejectedExecutionHandler) {
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat(properties.getPoolName() + "-pool-%d").build();
        //重写拒绝方法，采用blockingQueue的put方法，放入队列满了则等待，默认拒绝方法为满了则直接拒绝抛异常
        return new ThreadPoolExecutor(properties.getCorePoolSize(), properties.getMaxPoolSize(),
                properties.getKeepAliveSeconds(), TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(properties.getQueueSize()), namedThreadFactory, rejectedExecutionHandler);
    }


    /**
     * 默认拒绝执行处理程序、宿主服务未重写拒绝策略使用此拒绝策略
     *
     * @return {@link RejectedExecutionHandler}
     */
    @Bean
    @ConditionalOnMissingBean(value = RejectedExecutionHandler.class)
    public RejectedExecutionHandler defaultRejectedExecutionHandler() {
        return (runnable, executor) -> {
            try {
                if (!executor.isShutdown()) {
                    executor.getQueue().put(runnable);
                }
            } catch (InterruptedException e) {
                logger.error(Thread.currentThread().getName() + "executor error", e);
                new ThreadPoolExecutor.CallerRunsPolicy().rejectedExecution(runnable, executor);
            }
        };
    }


}
